#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include "../Headers/shared.h"
#include "../Headers/crazy.h"
#include "../Headers/comm_tcp.h"
#include "../Headers/comm_msgq.h"
#include "../Headers/comm_fifo.h"
#include "../Headers/comm_shm.h"

struct crazyCDT{
    char conn_type[CONN_TYPE_SIZE+1];
    void * conn_struct;
    void * adt_handler;
};

void * open_tcp_conn_struct (genHostT g_host);
void * open_msgq_conn_struct (genHostT g_host);
void * open_fifo_conn_struct (genHostT g_host);
void * open_shm_conn_struct (genHostT g_host);

/* ---------------------------- FUNCIONES ---------------------------------- */

crazyADT 
open_conn (genHostT g_host, const char * conn_type)
{
    crazyADT crazy;
    
    if (conn_type == NULL)
        return NULL;
    
    if ((crazy = malloc (sizeof(struct crazyCDT))) == NULL)
        return NULL;
        
    strcpy (crazy->conn_type, conn_type);
    
    /* TCP */
    if (!strncmp (conn_type, "TCP", strlen ("TCP"))){
        if ((crazy->conn_struct = open_tcp_conn_struct (g_host)) == NULL){
            free (crazy);
            return NULL;
        }
        if ((crazy->adt_handler = open_conn_tcp (crazy->conn_struct)) == NULL){
            free (crazy);
            free (crazy->conn_struct);
            return NULL;
        }
    }
    
    /* MSGQUEUES */
    else if (!strncmp (conn_type, "MSGQ", strlen ("MSGQ"))){
            if ((crazy->conn_struct = open_msgq_conn_struct (g_host)) == NULL){
            free (crazy);
            return NULL;
        }
        if ((crazy->adt_handler = open_conn_msgq (crazy->conn_struct)) == NULL){
            free (crazy);
            free (crazy->conn_struct);
            return NULL;
        }
    }
    
    /* FIFOS */
    else if (!strncmp (conn_type, "FIFO", strlen ("FIFO"))){
            if ((crazy->conn_struct = open_fifo_conn_struct (g_host)) == NULL){
            free (crazy);
            return NULL;
        }
        if ((crazy->adt_handler = open_conn_fifo (crazy->conn_struct)) == NULL){
            free (crazy);
            free (crazy->conn_struct);
            return NULL;
        }
    }    

    /* SHM */
    else if (!strncmp (conn_type, "SHM", strlen ("SHM"))){
            if ((crazy->conn_struct = open_shm_conn_struct (g_host)) == NULL){
            free (crazy);
            return NULL;
        }
        if ((crazy->adt_handler = open_conn_shm (crazy->conn_struct)) == NULL){
            free (crazy);
            free (crazy->conn_struct);
            return NULL;
        }
    }  
    return crazy;
}

int 
send_data (crazyADT crazy, char * s_msg, int size)
{
    if (!strncmp (crazy->conn_type, "TCP", strlen("TCP")))
        return send_data_tcp (crazy->adt_handler, s_msg, size);
    else if (!strncmp (crazy->conn_type, "MSGQ", strlen ("MSGQ")))
        return send_data_msgq (crazy->adt_handler, s_msg, size);
    else if (!strncmp (crazy->conn_type, "FIFO", strlen ("FIFO")))
        return send_data_fifo (crazy->adt_handler, s_msg, size);
    else if (!strncmp (crazy->conn_type, "SHM", strlen ("SHM")))
        return send_data_shm (crazy->adt_handler, s_msg, size);
}

int 
rcv_data (crazyADT crazy, char * r_msg, int size)
{
    if (!strncmp (crazy->conn_type, "TCP", strlen("TCP")))
        return rcv_data_tcp (crazy->adt_handler, r_msg, size);
    else if (!strncmp (crazy->conn_type, "MSGQ", strlen("MSGQ")))
        return rcv_data_msgq (crazy->adt_handler, r_msg, size);
    else if (!strncmp (crazy->conn_type, "FIFO", strlen("FIFO")))
        return rcv_data_fifo (crazy->adt_handler, r_msg);
    else if (!strncmp (crazy->conn_type, "SHM", strlen("SHM")))
        return rcv_data_shm (crazy->adt_handler, r_msg);
}

int 
close_conn (crazyADT crazy)
{
    if (!strncmp (crazy->conn_type, "TCP", strlen("TCP")))
        close_conn_tcp (crazy->adt_handler);
    else if (!strncmp (crazy->conn_type, "MSGQ", strlen("MSGQ")))
        close_conn_msgq (crazy->adt_handler);
    else if (!strncmp (crazy->conn_type, "FIFO", strlen("FIFO")))
        close_conn_fifo (crazy->adt_handler);
    else if (!strncmp (crazy->conn_type, "SHM", strlen("SHM")))
        close_conn_shm (crazy->adt_handler);
        
    free (crazy->conn_struct);
    free (crazy);
    return 1;
}

/* ------------------------------------------------------------------------- */
/* ------------------- Funciones Especiales -------------------------------- */

int
get_fd (crazyADT crazy)
{
    if (!strncmp (crazy->conn_type, "TCP", strlen("TCP"))){
        return getFd_tcp(crazy->adt_handler);
    }
    if (!strncmp (crazy->conn_type, "MSGQ", strlen("MSGQ"))){
        return getFd_msgq(crazy->adt_handler);
    }
    if (!strncmp (crazy->conn_type, "FIFO", strlen("FIFO"))){
    	return getRFd_fifo(crazy->adt_handler);
    }
}

/* ------------------------------------------------------------------------- */
/* ------------------- Funciones Auxiliares -------------------------------- */

void *
open_tcp_conn_struct (genHostT g_host)
{
    hostTCP * phost;
    
    if ((phost = malloc (sizeof (hostTCP))) == NULL)
        return NULL;
    
    phost->host_dir[9] = 0;
    phost->service[5] = 0;
    
    /* Copio los parametros en la estructura usada por TCP */
    strncpy(phost->host_dir, g_host.host_dir, strlen(TCP_HOST));
    strncpy(phost->service, g_host.service, strlen(TCP_PORT));
    
    return phost;
}

void *
open_msgq_conn_struct (genHostT g_host)
{
    hostMSGQ * phost;
    
    if ((phost = malloc (sizeof (hostMSGQ))) == NULL)
        return NULL;
    
    /* Copio los parametros en la estructura usada por MSGQ */
    phost->q_key = Q_KEY;
    
    return phost;
}

void *
open_fifo_conn_struct (genHostT g_host)
{
	hostFIFO * phost;
	
	if ((phost = malloc (sizeof (hostFIFO))) == NULL)
		return NULL;
	
	strcpy (phost->fifo_name, g_host.fifo_name);
	
	return phost;
}

void *
open_shm_conn_struct (genHostT g_host)
{
    hostSHM * phost;
    
    if ((phost = malloc (sizeof (hostSHM))) == NULL)
        return NULL;
    
    phost->shm_id = g_host.shm_id;
    phost->sem_id = g_host.sem_id;
    
    return phost;
}
